/**
 * BBD Service Inc
 * All Rights Reserved @2018
 */
package me.gavincook.moon.plugin.ui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

import com.intellij.execution.JavaExecutionUtil;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.EditorTextFieldWithBrowseButton;
import com.intellij.uiDesigner.core.GridConstraints;

import me.gavincook.moon.plugin.util.Pair;
import me.gavincook.moon.plugin.util.StringUtils;

/**
 * 结果面板
 *
 * @author gavincook
 * @version $ID: ResultContainerLabel.java, v0.1 2018-04-25 17:12 gavincook Exp $$
 */
public class JavaBeanConverterUI implements ProjectComponent {
    private JPanel              containerPanel;
    private JEditorPane         resultContentPanel;
    private JPanel              btnPanel;
    private JScrollPane         resultPanel;
    private JPanel              fromClassChooserPanel;
    private JLabel              fromClassLabel;
    private JPanel              fromClassChooser;
    private JLabel              toClassLabel;
    private JPanel              toClassChooserPanel;
    private JPanel              toClassChooser;
    private JButton             generateBtn;
    private JRadioButton        autoMethodNameRule;
    private JRadioButton        customMethodNameRule;

    /** 代码缩进 */
    private static final String CODE_INDENT = "    ";

    /**
     * 生成转换代码
     * @return
     */
    private String generateConvertCode(Project project) {
        EditorTextFieldWithBrowseButton fromClassChooserBtn = (EditorTextFieldWithBrowseButton) fromClassChooser;
        EditorTextFieldWithBrowseButton toClassChooserBtn = (EditorTextFieldWithBrowseButton) toClassChooser;

        //得到全限定名称
        String fromClassQualifiedName = fromClassChooserBtn.getText();
        String toClassQualifiedName = toClassChooserBtn.getText();

        //通过全限定名称找到对应的class
        PsiClass fromClass = JavaExecutionUtil.findMainClass(project, fromClassQualifiedName,
            GlobalSearchScope.projectScope(project));
        PsiClass toClass = JavaExecutionUtil.findMainClass(project, toClassQualifiedName,
            GlobalSearchScope.projectScope(project));

        if (fromClass == null) {
            Messages.showErrorDialog("原始类不存在", "异常");
            return null;
        }
        if (toClass == null) {
            Messages.showErrorDialog("目标类不存在", "异常");
            return null;
        }

        //获取简短名称
        String fromClassName = fromClass.getName();
        String toClassName = toClass.getName();

        //方法名
        Pair<String, String> methods = guessMethod(fromClassName, toClassName);

        //变量名字
        String fromVar = fromClassName.substring(0, 1).toLowerCase() + fromClassName.substring(1);
        String toVar = toClassName.substring(0, 1).toLowerCase() + toClassName.substring(1);

        StringBuilder code = new StringBuilder();

        //注释
        code.append(CODE_INDENT).append("/**").append("\n").append(CODE_INDENT).append(" * ").append(fromVar)
            .append("->").append(toVar).append("\n").append(CODE_INDENT).append(" *").append("\n").append(CODE_INDENT)
            .append(" * @param ").append(fromVar).append("\n").append(CODE_INDENT).append(" * @return ").append("\n")
            .append(CODE_INDENT).append(" */\n");

        code.append("public static ").append(toClassName).append(" ").append(methods.getFirst()).append("(")
            .append(fromClassName).append(" ").append(fromVar).append(") {\n").append(CODE_INDENT).append("if (")
            .append(fromVar).append(" == null) {\n").append(CODE_INDENT).append(CODE_INDENT).append("return null;\n")
            .append(CODE_INDENT).append("}\n").append(CODE_INDENT).append(toClassName).append(" ").append(toVar)
            .append(" = ").append("new ").append(toClassName).append("();\n");
        for (PsiMethod method : toClass.getAllMethods()) {
            //如果是setter方法，且原始类存在对应getter方法
            if (isSetterMethod(method) && isMethodExist(fromClass, getGetterMethodNameRelatedSetterMethod(method))) {
                code.append(CODE_INDENT).append(toVar).append(".").append(method.getName()).append("(").append(fromVar)
                    .append(".").append(getGetterMethodNameRelatedSetterMethod(method)).append("());\n");
            }
        }
        code.append(CODE_INDENT).append("return ").append(toVar).append(";\n}\n");

        //转换list
        String fromVarList = fromVar + "List";
        String toVarList = toVar + "List";

        code.append("\n");

        //注释
        code.append(CODE_INDENT).append("/**").append("\n").append(CODE_INDENT).append(" * ").append(fromVarList)
            .append("->").append(toVarList).append("\n").append(CODE_INDENT).append(" *").append("\n")
            .append(CODE_INDENT).append(" * @param ").append(fromVarList).append("\n").append(CODE_INDENT)
            .append(" * @return ").append("\n").append(CODE_INDENT).append(" */\n");

        code.append("public static List<").append(toClassName).append("> ").append(methods.getSecond()).append("(List<")
            .append(fromClassName).append("> ").append(fromVarList).append(") {\n").append(CODE_INDENT).append("if (")
            .append(fromVarList).append(" == null) {\n").append(CODE_INDENT).append(CODE_INDENT)
            .append("return null;\n").append(CODE_INDENT).append("}\n").append(CODE_INDENT).append("List<")
            .append(toClassName).append("> ").append(toVarList).append(" = new ArrayList<>();\n").append(CODE_INDENT)
            .append("for ( ").append(fromClassName).append(" ").append(fromVar).append(" : ").append(fromVarList)
            .append("){\n").append(CODE_INDENT).append(CODE_INDENT).append(toVarList).append(".add(")
            .append(methods.getFirst()).append("(").append(fromVar).append("));\n").append(CODE_INDENT).append("}\n")
            .append(CODE_INDENT).append("return ").append(toVarList).append(";\n").append("}");
        return code.toString();
    }

    /**
     * 猜测方法名
     * @param fromClassName
     * @param toClassName
     * @return
     */
    private Pair<String, String> guessMethod(String fromClassName, String toClassName) {
        //先取得公共前缀
        String prefix = StringUtils.getLongestCommonPrefix(new String[] { fromClassName, toClassName });

        String from = fromClassName;
        String to = toClassName;
        if (prefix != null) {
            from = fromClassName.substring(prefix.length());
            to = toClassName.substring(prefix.length());
        }
        //单一对象转换方法名
        StringBuilder singleMethod = new StringBuilder("convert");
        //集合对象转换方法名
        StringBuilder listMethod = new StringBuilder("convert");
        singleMethod.append(from).append("2").append(to);
        listMethod.append(from).append("s2").append(to).append("s");

        return new Pair<String, String>(singleMethod.toString(), listMethod.toString());
    }

    /**
     * 检查类中是否有指定名称的方法
     * @param psiClass
     * @param methodName
     * @return
     */
    private boolean isMethodExist(PsiClass psiClass, String methodName) {
        for (PsiMethod method : psiClass.getAllMethods()) {
            if (methodName.equals(method.getName())) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查方法是否为setter方法
     * @param method
     * @return
     */
    private boolean isSetterMethod(PsiMethod method) {
        return method.getName().startsWith("set");
    }

    /**
     * 获取setter方法对应的getter方法名称
     * @param method
     * @return
     */
    private String getGetterMethodNameRelatedSetterMethod(PsiMethod method) {
        return "get" + method.getName().substring(3);
    }

    /**
     * 创建类选择器
     */
    public void createClassChooserIfNecessary(final Project project) {
        GridConstraints gridConstraints = new GridConstraints();
        gridConstraints.setRow(0);
        gridConstraints.setColumn(1);
        gridConstraints.setFill(1);
        gridConstraints.setHSizePolicy(6);
        if (this.fromClassChooser == null) {
            this.fromClassChooser = createClassChooser("请选择原始类", project);
            this.fromClassChooserPanel.add(fromClassChooser, gridConstraints);
        }
        if (this.toClassChooser == null) {
            this.toClassChooser = createClassChooser("请选择目标类", project);
            this.toClassChooserPanel.add(toClassChooser, gridConstraints);
        }
        generateBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String resultCode = generateConvertCode(project);
                resultContentPanel.setText(resultCode);
            }
        });

        ButtonGroup group = new ButtonGroup();
        group.add(autoMethodNameRule);
        group.add(customMethodNameRule);
    }

    /**
     * 创建类选择器
     *
     * @param title
     * @return
     */
    private EditorTextFieldWithBrowseButton createClassChooser(final String title, final Project project) {

        final EditorTextFieldWithBrowseButton classChooser = new EditorTextFieldWithBrowseButton(project, true);

        //设置点击事件
        classChooser.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                TreeClassChooser treeClassChooser = TreeClassChooserFactory.getInstance(project)
                    .createProjectScopeChooser(title);
                treeClassChooser.showDialog();
                PsiClass psiClass = treeClassChooser.getSelected();
                if (psiClass != null) {
                    classChooser.setText(psiClass.getQualifiedName());
                }
            }
        });

        return classChooser;
    }

    /**
     * 获取容器面板
     *
     * @return
     */
    public JPanel getContainerPanel() {
        return containerPanel;
    }
}
